package com.jsu.user.service.impl;

import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jsu.user.mapper.WebUserMapper;
import com.jsu.user.service.LoginService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.net.openssl.ciphers.Authentication;
import org.example.model.common.dtos.ResponseResult;
import org.example.model.common.enums.RedisCodeEnum;
import org.example.model.common.enums.WebHttpCodeEnum;
import org.example.model.user.dto.ForgetDto;
import org.example.model.user.dto.LoginDto;
import org.example.model.user.dto.RegisterDto;
import org.example.model.user.dto.UserInfoDto;
import org.example.model.user.pojo.User;
import org.example.utils.common.ALiYunCodeUtil;
import org.example.utils.common.IdsUtils;
import org.example.utils.common.WebJwtUtil;
import org.example.utils.common.RedisCache;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import static org.example.model.common.enums.RedisCodeEnum.*;


@Service
@Slf4j
@Transactional
public class WebLoginServiceImpl extends ServiceImpl<WebUserMapper, User> implements LoginService {
    @Autowired
    private StringRedisTemplate redisCache;
    @Autowired
    private WebLoginServiceImpl webLoginService;
    @Autowired(required = false)
    private ALiYunCodeUtil aLiYunCodeUtil;
    @Autowired
    private WebUserMapper webUserMapper;
    @Autowired
    private PointDetailServiceImpl pointDetailService;
    @Autowired
    private HttpServletResponse response;
    final private ObjectMapper mapper = new ObjectMapper();


    /**
     * web端用户登录
     * @param loginDto
     * @return
     */
    @Override
    public ResponseResult loginUser(LoginDto loginDto) {
        //正常登录
        if(StringUtils.isNotBlank(loginDto.getPassword())&&StringUtils.isNotBlank(loginDto.getPhone())) {
            //根据手机号查询用户
            User user = getOne(Wrappers.<User>lambdaQuery().eq(User::getTel, loginDto.getPhone()));
            if(user==null)
                return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST,"用户信息不存在");
            //密码加密
            String salt = user.getSalt();
            String password = loginDto.getPassword();
            String pwd = DigestUtils.md5DigestAsHex((password + salt).getBytes());
            //更新loginDto中的密码
            loginDto.setPassword(pwd);
            //比对密码
            if (!webUserMapper.selectByPhone(loginDto.getPhone()).getPassword().equals(pwd)) {
                return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST);
            }
            //根据手机号生成token
            String jwt = WebJwtUtil.getToken(Long.valueOf(loginDto.getPhone()));
            String longToken = WebJwtUtil.getLongToken(Long.valueOf(loginDto.getPhone()));
            log.info("生成token:"+jwt);
            log.info("生成longToken:"+longToken);
            String dto = null;
            try {
                dto = mapper.writeValueAsString(loginDto);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            redisCache.opsForValue().set(LOGIN.getMsg() +loginDto.getPhone(),dto,2, TimeUnit.DAYS);
            HashMap<String,Object> token = new HashMap<>();
            token.put("token",jwt);
            token.put("longToken",longToken);
            //返回token和用户信息
            UserInfoDto userInfoDto = new UserInfoDto();
            BeanUtils.copyProperties(user,userInfoDto);
            log.info(userInfoDto.toString());
            boolean isSign = pointDetailService.isSign(user.getPkId());
            userInfoDto.setSignIn(isSign);
            token.put("user",userInfoDto);
            return ResponseResult.okResult(token);
        }else{
            //游客登录
            Map<String, Object> map = new HashMap<>();
            map.put("token", WebJwtUtil.getToken(0L));
            return ResponseResult.okResult(map);
        }
    }
    /**
     * web端用户注册
     * @param registerDto
     * @return
     */
    @Override
    public ResponseResult register(RegisterDto registerDto) {
        //从redis中获取验证码
        String redisKey = RedisCodeEnum.REGISTER_EMAIL.getMsg()+registerDto.getPhone();
        Integer code = Integer.valueOf(redisCache.opsForValue().get(redisKey));
        log.info(registerDto.toString());
        log.info("redis中的验证码为："+code);
        //判断验证码是否相同
        if(!code.equals(registerDto.getCode())){
            return ResponseResult.errorResult(WebHttpCodeEnum.PARAM_INVALID,"验证码错误");
        }
        //生成id和用户盐值
        int id = IdsUtils.creatCodeTen();
        String salt = "abc";
        try {
            salt = IdsUtils.encryptNumber(2L);
        } catch (Exception e) {
            log.info("生成盐值");
            throw new RuntimeException(e);
        }
        //封装user对象
        User user = new User();
        user.setPkId(id);
        user.setSalt(salt);
        user.setUsername("用户"+id);
        String pwd = DigestUtils.md5DigestAsHex((registerDto.getPassword() + salt).getBytes());
        user.setPassword(pwd);
        user.setTel(registerDto.getPhone());
        //存入数据库
        int count = webUserMapper.insert(user);
        if(count>0)
            return ResponseResult.okResult(user);

        return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"注册失败");
    }
    /**
     * web端用户注册时发送验证码
     * @param phone
     * @return
     */
    @Override
    public ResponseResult registerEmail(String phone){
        //生成验证码，发送邮件
        String code = IdsUtils.creatCode();
        log.info("开始发送邮件");
        try {
            aLiYunCodeUtil.sendMail(phone,code);
        } catch (ClientException e) {
            throw new RuntimeException(e);
        }
        log.info("发送成功");
        log.info("手机号"+phone+"      验证码："+code);
        //存入Redis中
        redisCache.opsForValue().set(RedisCodeEnum.REGISTER_EMAIL.getMsg()+phone,code,60, TimeUnit.SECONDS);
        return ResponseResult.okResult(code);
    }

    /**
     * web端忘记密码时发送验证码
     * @param phone
     * @return
     */
    @Override
    public ResponseResult forgetPassword(String phone) {
        //生成验证码，发送邮件
        String code = IdsUtils.creatCode();
        log.info("开始发送邮件");
        try {
            aLiYunCodeUtil.sendForgetMail(phone,code);
        } catch (ClientException e) {
            throw new RuntimeException(e);
        }
        log.info("发送成功");
        log.info("手机号"+phone+"      验证码："+code);
        //存入Redis中
        redisCache.opsForValue().set(FORGET_PASSWORD.getMsg()+phone,code,60, TimeUnit.SECONDS);
        return ResponseResult.okResult(code);
    }

    /**
     * web端忘记密码时修改密码
     * @param forgetDto
     * @return
     */
    @Override
    public ResponseResult changePassword(ForgetDto forgetDto) {
        log.info(forgetDto.toString());
        //判断验证码是否正确
        String redisKey = FORGET_PASSWORD.getMsg()+forgetDto.getPhone();
        String code = redisCache.opsForValue().get(redisKey);
        log.info("redis中的验证码为："+code);
        log.info("用户输入的验证码为："+forgetDto.getCode());
        if(!forgetDto.getCode().equals(code)){
            return ResponseResult.errorResult(WebHttpCodeEnum.PARAM_INVALID,"验证码错误");
        }
        //根据手机号查询用户
        User user = getOne(Wrappers.<User>lambdaQuery().eq(User::getTel, forgetDto.getPhone()));
        if(user==null)
            return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST,"用户信息不存在");
        //密码加密
        String salt = user.getSalt();
        String password = forgetDto.getPwd();
        String pwd = DigestUtils.md5DigestAsHex((password + salt).getBytes());
        //更新密码
        user.setPassword(pwd);
        int count = webUserMapper.updateById(user);
        if(count>0)
            return ResponseResult.okResult(user);
        return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"修改密码失败");
    }


}
